#include <fdc.h>
#include <std.h>
#include <pio.h>
#include <error.h>
#include <biosdisk.h>
#include <diskfmt.h>
#include <memory.h>
#include <irq.h>
#include <timer.h>
#include <type.h>
#include <vol.h>

/*The different volume system type codes from GRUB docs..:*/
/*		0		1		2		3		4		5		6		7		8		9		a		b		c		d		e		f */
char *pt[]={ \
/*0*/ "Empty","FAT12","XENIX","XENIX","FAT16","DOSEx","FAT16","NTFS ","AIX	","AIX  ","OS/2B","FAT32","FAT32","		","FAT16","W95ex", \
/*1*/ "OPUS ","fat12","Compq","		","FAT16","		","FAT16","NTFS ","AST  ","		","		","		","		","		","		","		", \
/*2*/ "		","		","		","		","NEC  ","		","		","		","		","		","		","		","		","		","		","		", \
/*3*/ "		","		","		","		","		","		","		","		","		","		","		","		","pmagr","		","		","		", \
/*4*/ "VENIX","LINUX","SFS  ","Linux","		","		","		","		","		","		","		","		","		","		","		","		", \
/*5*/ "DM   ","DM6  ","CP/M ","DM6  ","DM6  ","EZ-dr","Goldb","	","		","		","		","		","Priam","		","		","		", \
/*6*/ "		","Speed","		","GNUhu","Novel","Novel","		","		","		","		","		","		","		","		","		","		", \
/*7*/ "DiskS","		","		","		","		","PC/IX","		","QNX4.","QNX4.","QNX4.","		","		","		","		","		","		", \
/*8*/ "MINIX","MINIX","LINUX","LINUX","OS/2 ","LINUX","NTFSv","NTFSv","	","		","		","		","		","		","		","		", \
/*9*/ "		","		","		","Amoeb","Amoeb","		","		","		","		","		","		","		","		","		","		","		", \
/*a*/ "IBMth","		","		","		","		","BSD  ","		","NextS","		","		","		","		","		","		","		","		", \
/*b*/ "		","		","		","		","		","		","		","BSDI ","BSDI ","		","		","		","		","		","		","		", \
/*c*/ "		","DRDOS","		","		","DRDOS","		","DRDOS","Syrin","		","		","		","		","		","		","		","		", \
/*d*/ "		","		","		","		","		","		","		","		","		","		","		","CP/M ","		","		","		","		", \
/*e*/ "		","DOS  ","		","DOS  ","Speed","		","		","		","		","		","		","		","		","		","		","		", \
/*f*/ "		","Speed","DOS3.","		","Speed","		","		","		","		","		","		","		","		","		","Speed","Xenix"};

/*A partition table entry*/
static struct pentry	{
	u8 boot;
	u8 bhead;
	u8 bsecthcyl;
	u8 blcyl;
	u8 sys;
	u8 ehead;
	u8 esecthcyl;
	u8 elcyl;
	u32 preceding_sectors;
	u32 nsect;
}__attribute__ ((packed))part[16];

struct partition	{
	struct pentry p;
	u32 start_lba;
	u32 size_lba;
	struct partition *next;
}*partitions=NULL;

	
//partition table management code


#define SECT_SIZE 512


static u32 extoff=0;

void add_partition(struct pentry *x,u32 start_lba,u32 size_lba)
{
	struct partition *temp;
	if(!partitions) {
		partitions=new(struct partition);
		temp=partitions;
	} else {
		for(temp=partitions;temp->next!=NULL;temp=temp->next);
		temp->next=new(struct partition);
		temp=temp->next;
	}
	temp->next=NULL;
	memcpy(&temp->p,x,sizeof(struct pentry));
	temp->start_lba=start_lba;
	temp->size_lba=size_lba;
}

int read_ptextended(u32 lba)
{
	int i;
	struct pentry *x;
	u8 *buffer;
	buffer=(u8 *)get_mem(SECT_SIZE);
	if(read_drive(buffer,lba,1)<0)	{
		printk("\nCannot read disk lba:%d",lba);
		return FAILED;
	}
	for(i=0;i<4;i++)	{
		x=(struct pentry *)(buffer+POFF1+i*0x10);
		if(x->sys==0x5 || x->sys==0xf)	{
			read_ptextended(extoff+x->preceding_sectors);
		} else	if(x->sys)	{
			add_partition(x,lba+x->preceding_sectors,x->nsect);
		}
	}
	free(buffer);
	return NULL;
}

int read_pt(u32 lba)
{
	int i;
	struct pentry *x;
	u8 *buffer;
	buffer=(u8 *)get_mem(SECT_SIZE);
	if(read_drive(buffer,lba,1)<0)	{
		printk("\nCannot read:%d",lba);
		return FAILED;
	}
	if((u16)(*((u16 *)(buffer+0x1fe)))!=0xaa55)	{
		printk("\nSector invalid. Signature!=0xaa55");
		return FAILED;
	}
	for(i=0;i<4;i++)	{
		x=(struct pentry *)(buffer+POFF1+i*0x10);
		if(x->sys==0x5 || x->sys==0xf)	{
			extoff=x->preceding_sectors;
			read_ptextended(x->preceding_sectors);
		} else	if(x->sys)	{
			add_partition(x,x->preceding_sectors,x->nsect);
		}
	}
	free(buffer);
	return NULL;
}

/*Reads partition table LBA 0*/
int read_table()
{
	int i;
	printk("\nReading partition table...");
	read_pt(0);
	return NULL;
}

/*This function returns a disk volume by number--It returns the filled volume structure*/
int get_disk_volume(disk_volume *new_vol,int volno)
{
	if(part[volno].sys==NULL)	{
		new_vol->start_lba=NULL;
		new_vol->len_lba=NULL;
		return FAILED;
	}
	new_vol->start_lba=part[volno].preceding_sectors;
	new_vol->len_lba=part[volno].nsect;
	printk("\nGet disk volume:%x",part[volno].sys);
	return NULL;
}

char *voldeperr="diskvol:driver dependency error";
int init_vol()
{
	struct partition *temp;
	read_table();
	printk("\nPartitions:");
	for(temp=partitions;temp!=NULL;temp=temp->next)	{
		printk("%s ",pt[temp->p.sys]);
	}
	return NULL;
}
